package com.im.sdk.android;

import com.im.common.ImConstant;
import com.im.common.Request;
import com.im.protocol.AuthenticateRequestProto;
import com.im.protocol.GroupMessageRequestProto;
import com.im.protocol.MessageRequestProto;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;

import java.util.HashMap;
import java.util.Map;

/**
 * @Created leijun
 * @Date 2021/9/11 7:59 上午
 */
public class ImClient {
    /**
     * 客户端sdk版本号
     */
    private static final int APP_SDK_VERSION = 1;
    /**
     * 消息默认序号
     */
    private static final int SEQUENCE_DEFAULT = 1;

    // 代表客户端连接的线程池
    private EventLoopGroup eventLoopGroup;
    // 代表一个客户端
    private Bootstrap client;
    private ChannelFuture channelFuture;
    private SocketChannel socketChannel;

    /**
     * 客户端发起一个连接
     * @param host
     * @param port
     * @throws InterruptedException
     */
    public void connect(String host, Integer port) throws InterruptedException {
        this.eventLoopGroup = new NioEventLoopGroup(1);
        this.client = new Bootstrap();
        this.client.group(eventLoopGroup)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ByteBuf delimiter = Unpooled.copiedBuffer(ImConstant.DELIMITER);
                        socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(4096, delimiter));
                        socketChannel.pipeline().addLast(new ImClientHandler(ImClient.this));
                    }
                });
        this.channelFuture = this.client.connect(host, port).sync();
        System.out.println("客户端发起连接。。。");
        this.channelFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    System.out.println("客户端与服务端连接成功！");
                    socketChannel = (SocketChannel) channelFuture.channel();
                } else {
                    System.out.println("客户端与服务端连接失败！");
                    channelFuture.channel().close();
                    eventLoopGroup.shutdownGracefully();
                }
            }
        });
    }

    /**
     * 发起用户认证
     * @param uid
     * @param token
     */
    public void authenticate(Long uid, String token) {
        // 封装请求体
        AuthenticateRequestProto.AuthenticateRequest.Builder authenticateRequestBuilder =
                AuthenticateRequestProto.AuthenticateRequest.newBuilder();
        AuthenticateRequestProto.AuthenticateRequest authenticateRequest =
                authenticateRequestBuilder.setUid(uid)
                .setToken(token)
                .setTimestamp(System.currentTimeMillis())
                .build();
        Request request = new Request(APP_SDK_VERSION, ImConstant.REQUEST_TYPE_AUTHENTICATE, SEQUENCE_DEFAULT, authenticateRequest.toByteArray());
        this.socketChannel.writeAndFlush(request.getBuf());
        System.out.println("客户端【"+uid+"】发起客户认证请求");
    }

    /**
     * 发送单聊消息
     * @param senderId
     * @param receiverId
     * @param content
     */
    public void sendMessage(Long senderId, Long receiverId, String content) {
        MessageRequestProto.MessageRequest.Builder messageRequestBuilder =
                MessageRequestProto.MessageRequest.newBuilder();
        MessageRequestProto.MessageRequest messageRequest =
                messageRequestBuilder.setSenderId(senderId)
                .setReceiverId(receiverId)
                .setContent(content)
                .build();
        Request request = new Request(APP_SDK_VERSION, ImConstant.REQUEST_TYPE_SEND_MESSAGE,
                SEQUENCE_DEFAULT, messageRequest.toByteArray());
        this.socketChannel.writeAndFlush(request.getBuf());
        System.out.println("客户端【"+senderId+"】发送一条消息："+content);
    }

    /**
     * 发送群聊消息
     * @param senderId
     * @param groupId
     * @param content
     */
    public void sendGroupMessage(Long senderId, Long groupId, String content) {
        GroupMessageRequestProto.GroupMessageRequest.Builder builder =
                GroupMessageRequestProto.GroupMessageRequest.newBuilder();
        GroupMessageRequestProto.GroupMessageRequest groupMessageRequest =
                builder.setSenderId(senderId)
                        .setGroupId(groupId)
                        .setContent(content)
                        .build();
        Request request = new Request(APP_SDK_VERSION, ImConstant.REQUEST_TYPE_GROUP_MESSAGE,
                SEQUENCE_DEFAULT, groupMessageRequest.toByteArray());
        this.socketChannel.writeAndFlush(request.getBuf());
    }

    /**
     * 重新选择一个接入系统进行连接
     */
    public void reconnect() throws InterruptedException {
        System.out.println("重新连接...");
        String host = "";
        int port = -1;
        connect(host, port);
        authenticate(0L, "");
    }

    /**
     * 关闭客户端
     */
    public void close() {
        this.socketChannel.shutdown();
        this.eventLoopGroup.shutdownGracefully();
    }
}
